//shortcut to BaseEnum.getClause
var baseEnum_getClause,
// default expression to value clauses
default_clauses_returnCurrent = jMass.expr("x => x"),
// default expression to equality comparer
default_clauses_equalityComparer = jMass.expr("x,y => x === y");

jMass.extend( {
	// sort comparer methods
	$comparers : {},

	regSortComparer : function(name, fn) {
		this.$comparers[name] = fn;
	},

	getSortComparer : function(name) {
		return this.$comparers[name];
	},

	// return an Enumerator object for obj.
	getEnum : function(obj) {
		// return obj if it is an Enumerator;
	return !obj ? null : obj.isEnum ? obj
	// or, if obj has the toEnum method, call it.
			: obj.toEnum ? obj.toEnum() : null;
},

// to hold enumerators classes
	Enum : {
		// enumerators classes
		$classes : [],
		// enumerators methods
		$methods : []
	},

	// register a new enum class
	regEnumClass : function(name, classObj) {
		jMass.Enum.$classes.push( {
			name : name,
			obj : classObj
		});
	},

	// register a enumerator method
	regEnumMethod : function(name, method) {
		jMass.Enum.$methods.push( {
			name : name,
			method : method
		});
	},

	$initEnums : function() {
		// variables in for statement
	var cls, mthd, obj, isEn;

	for ( var i = 0, len = this.Enum.$classes.length; i < len; i++) {
		cls = this.Enum.$classes[i];
		obj = cls.obj;
		isEn = obj.prototype.isEnum === true;

		if (isEn)
			this.Enum[cls.name] = obj;

		// implement
	for ( var j = 0, lenj = this.Enum.$methods.length; j < lenj; j++) {
		mthd = this.Enum.$methods[j];
		if (obj.prototype[mthd.name] == undefined) {
			if (isEn)
				obj.prototype[mthd.name] = mthd.method;
			obj.prototype["_" + mthd.name] = mthd.method;
		}
	}
}
},

init : function(o) {
this.$initEnums();
}
});

// define the enumerator base object
var BaseEnum = jMass.Enum.BaseEnum = jMass.define( {
	// isEnum
	isEnum : true,

	// name of enumerator
	name : "enumerator",

	// store a unique id for this enumerator
	guid : 0,

	// the source object that provide the data to enumerate
	source : null,

	// current item
	current : null,

	// next() function
	// MUST return true when new value is assigned to this.current.
	// ** commented here for sake of speed
	// next: function() { return false; },

	// reset enumerator state
	// reset: function() { },

	// perform some initialization code for enumerator
	constructor : function(source) {
		// assign a unique id
		this.guid = ++jMass.guid;

		this.source = source;

		// reset the enumerator
		this.reset();
	},

	getClause : function(clause, defaultIfEmpty) {
		return jMass.getExpr(clause || defaultIfEmpty);
	},

	// toEnum
	toEnum : function() {
		return this;
	}
});

baseEnum_getClause = jMass.Enum.BaseEnum.prototype.getClause;

/* base enumerator */
var fluentQryBaseEnum = jMass.Enum.BaseFluentEnum = BaseEnum.extend( {
	// override base constructor
	constructor : function(source, a, b, c) {
		// call base passing source enumerator
		this.base(jMass.getEnum(source));

		// call prepare method
		if (this.prepare)
			this.prepare.call(this, a, b, c);

		// reset
		this.reset();
	},
	// constructor will call prepare on decendants.
	// ** commented here for sake of speed
	// prepare: function() { },
	reset : function() {
		this.source.reset();
		this.current = this.source.current;
	}
});

/*
 * register default sort comparers: string, number and boolean e cast
 */

jMass.regSortComparer("string", function(x, y) {
	if (x > y)
		return 1;
	else if (x < y)
		return -1;
	else
		return 0;
});

jMass.regSortComparer("number", function(x, y) {
	return x - y;
});

jMass.regSortComparer("boolean", function(x, y) {
	if (x == y)
		return 0;
	else if (x)
		return -1;
	else
		return 1;
});

jMass.regSortComparer("cast",
		function(x, y) {
			var xtype, ytype, xIsPrim, yIsPrim;
			xtype = typeof x;
			ytype = typeof y;
			xIsPrim = xtype === "string" || xtype === "number"
					|| xtype === "boolean";
			yIsPrim = ytype === "string" || ytype === "number"
					|| ytype === "boolean";

			if (xIsPrim && yIsPrim) {
				if (xtype === "number")
					return ytype === "number" ? jMass.$comparers[xtype](x, y)
							: -1;
				else if (xtype === "string") {
					if (ytype === "number")
						return 1;
					else
						return ytype === "string" ? jMass.$comparers[xtype](x,
								y) : -1;
				} else if (xtype === "boolean") {
					if (ytype === "number" || ytype === "string")
						return 1;
					else
						return ytype === "boolean" ? jMass.$comparers[xtype](x,
								y) : -1;
				}
			} else if (!xIsPrim && !yIsPrim)
				return 0;
			else if (!xIsPrim)
				return 1;
			else
				return -1;
		});
